/**
 * Created 2008.01.30
 */
package bancosys.tec.rtm.impl.exception.dao;

import static org.hibernate.criterion.MatchMode.ANYWHERE;

import java.util.Calendar;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.rtm.exception.ExceptionFinder;
import bancosys.tec.rtm.exception.RTMException;
import bancosys.tec.rtm.impl.exception.domain.ExceptionRecord;
import bancosys.tec.utils.date.Timestamp;

/**
 * @author piercio
 */
public class ExceptionRecordDAO extends BaseDAO<ExceptionRecord> implements ExceptionFinder {

    /**
     * Retorna o exceptionRecord designado por id.
     * 
     * @param id o id do exceptionRecord.
     * @return o exceptionRecord.
     * @throws RTMException caso o registro não exista.
     */
    public ExceptionRecord find(long id) throws RTMException {
        try {
            return super.findByPk(id);
        } catch (BeanNotFoundException e) {
            throw new RTMException(e);
        }
    }

    /**
     * Retorna uma lista com os exceptionRecords cujo campo id seja maior que o passado como parâmetro.
     * 
     * @param id o id de referência.
     * @return uma lista de exceptionRecords.
     * @throws RTMException caso haja problema na busca.
     */
    public List<ExceptionRecord> findAllTracesAfterId(long id) throws RTMException {
        Criteria criteria = this.getSession().createCriteria(this.getPersistableClass());
        criteria.add(Restrictions.gt("id", id));
        List<ExceptionRecord> result = this.executeQuery(criteria);
        return result;
    }

    /**
     * Retorna uma lista de exceptionRecords ocorridos durante o dia determinado pela data, ordenada de forma decrescente (o primeiro
     * elemento é o mais recente).
     * 
     * @param date a data que determina o dia selecionado. Horário é ignorado.
     * @return uma lista de exceptionRecords.
     * @throws RTMException caso haja problema na busca.
     */
    public List<ExceptionRecord> findByDate(Timestamp date) throws RTMException {
        if (date == null) {
            return null;
        }
        Criteria criteria = this.getSession().createCriteria(this.getPersistableClass());
        criteria.add(Restrictions.between("timestamp", new Timestamp(date.getYear(), date.getMonth(), date.getDay(), 0, 0, 0, 0),
                new Timestamp(date.getYear(), date.getMonth(), date.getDay() + 1, 0, 0, 0, 0)));
        criteria.addOrder(Order.desc("timestamp"));
        List<ExceptionRecord> result = this.executeQuery(criteria);
        return result;
    }

    /**
     * Retorna uma lista de exceptionRecords ocorridos durante o dia determinado pela data, ordenada de forma decrescente (o primeiro
     * elemento é o mais recente). Mantido para retro compatibilidade.
     * 
     * @param date a data que determina o dia selecionado. Horário é ignorado.
     * @return uma lista de exceptionRecords.
     * @throws RTMException casao haja problema na busca.
     */
    public List<ExceptionRecord> findByDate(Calendar date) throws RTMException {
        if (date == null) {
            return null;
        }
        return this.findByDate(new Timestamp(date));
    }

    /**
     * Retorna o id máximo das exceptionRecords.
     * 
     * @return o id máximo.
     * @throws RTMException caso haja problema na busca.
     */
    public long findMaxId() throws RTMException {
        Criteria criteria = this.createCriteria();
        criteria.setProjection(Projections.max("id"));

        @SuppressWarnings("unchecked")
        List<Long> result = criteria.list();
        if (result != null && result.size() > 0) {
            Long valor = result.get(0);
            if (valor == null) {
                return 0;
            }
            return valor.longValue();
        }
        return 0;
    }

    /**
     * Retorna uma lista com todos os exceptionRecords que obedeçam os parâmetros especificados. Caso algum parâmetro seja null (ou -1, veja
     * abaixo), ele será ignorado na busca.
     * 
     * @param fatoIdStart id mínimo (-1 para sem mínimo).
     * @param fatoIdEnd id máximo (-1 para sem máximo).
     * @param startDate data mínima para as exceções.
     * @param finalDate data máxima para as exceções.
     * @param horarioStart hora inicial, usado em conjunto com starDate. Formato: "hh:mm"
     * @param horarioEnd hora final, usado em conjunto com finalDate. Formato: "hh:mm"
     * @param user - user
     * @param system - system
     * @return uma lista de exceptinRecords.
     * @throws RTMException caso haja problema na busca.
     */
    @SuppressWarnings({ "deprecation" })
    public List<ExceptionRecord> findTraces(long fatoIdStart, long fatoIdEnd, Calendar startDate, Calendar finalDate, String horarioStart,
            String horarioEnd, String user, String system) throws RTMException {
        Criteria criteria = this.getSession().createCriteria(this.getPersistableClass());

        if (fatoIdStart != -1) {
            criteria.add(Restrictions.ge("id", fatoIdStart));
        }
        if (fatoIdEnd != -1) {
            criteria.add(Restrictions.le("id", fatoIdEnd));
        }

        if (!StringUtils.isBlank(user)) {
            criteria.add(Restrictions.ilike("user", user, ANYWHERE));
        }
        if (!StringUtils.isBlank(system)) {
            criteria.add(Restrictions.ilike("system", system, ANYWHERE));
        }

        if (startDate != null) {
            Timestamp tsInicial = new Timestamp(startDate);
            tsInicial.setSeconds(0);
            tsInicial.setNanos(0);
            if (horarioStart != null && !horarioStart.equals("")) {
                String[] horario = horarioStart.split(":");
                if (horario.length >= 2) {
                    int horas = Integer.parseInt(horario[0]);
                    int minutos = Integer.parseInt(horario[1]);
                    tsInicial.setHours(horas);
                    tsInicial.setMinutes(minutos);
                }
            } else {
                tsInicial.setHours(0);
                tsInicial.setMinutes(0);
            }
            criteria.add(Restrictions.ge("timestamp", tsInicial));
        }

        if (finalDate != null) {
            Timestamp tsFinal = new Timestamp(finalDate);
            tsFinal.setSeconds(0);
            tsFinal.setNanos(0);
            if (horarioEnd != null && !horarioEnd.equals("")) {
                String[] horario = horarioEnd.split(":");
                if (horario.length >= 2) {
                    int horas = Integer.parseInt(horario[0]);
                    int minutos = Integer.parseInt(horario[1]);
                    tsFinal.setHours(horas);
                    tsFinal.setMinutes(minutos);
                }
            } else {
                tsFinal.addDays(1);
                tsFinal.setHours(0);
                tsFinal.setMinutes(0);
            }
            criteria.add(Restrictions.le("timestamp", tsFinal));
        }
        criteria.addOrder(Order.desc("timestamp"));
        List<ExceptionRecord> result = this.executeQuery(criteria);
        return result;
    }
}